package com.tiger.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.tiger.utils.DateTimeUtils;
import com.tiger.utils.MD5Utils;
import com.tiger.utils.Sync2ElasticsearchUtils;
import com.tiger.utils.UpdateUtils;
import com.tiger.mapper.base.BlinkMapper;
import com.tiger.mapper.base.ErrorMapper;
import com.tiger.mapper.base.QuestionMapper;
import com.tiger.mapper.homePage.HotArticleMapper;
import com.tiger.pojo.base.Blink;
import com.tiger.pojo.base.Error;
import com.tiger.pojo.base.Question;
import com.tiger.pojo.homePage.HotArticle;
import com.tiger.pojo.publicPage.Article;
import com.tiger.pojo.publicPage.BlinkInfo;
import io.minio.*;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author HuXuehao (StudiousTiger)
 * @desc 这个类的作用是
 * @date 2022/3/1
 */
@Slf4j
@RestController
public class PublishPageController {
    @Autowired
    private MinioClient minioClient;
    @Autowired
    private HttpServletRequest httpServletRequest;
    @Autowired
    private ErrorMapper errorMapper;
    @Autowired
    private QuestionMapper questionMapper;
    @Autowired
    private HotArticleMapper hotArticleMapper;
    @Autowired
    private BlinkMapper blinkMapper;
    @Autowired
    private Sync2ElasticsearchUtils sync2EsUtils;

    @Autowired
    private UpdateUtils updateUtil;
    @Value("${minio.bucketNameOfMdFile}")
    private String bucketNameOfMdFile;
    @Value("${minio.bucketNameOfMdPicture}")
    private String bucketNameOfMdPicture;
    @Value("${minio.endPoint}")
    private String endPoint;


    /**
     * 上传MakeDown中的图片到minio，并返回上传图片的URL
     * @param file
     * @return
     */
    @RequestMapping(value = "/publishPage/putMdFileOfPicture", name = "上传MakeDown中的图片到服务器/user")
    public String putMdFileOfPicture(@RequestParam(name = "file", required = false) MultipartFile file){
        if (file == null){
            return "false";
        }
        String originalFilename = file.getOriginalFilename();  // 获取上传的文件名
        String fileType = originalFilename.substring(originalFilename.lastIndexOf("."));  // 获取文件类型（例如：.jpg）
        String fileName = MD5Utils.string2MD5(originalFilename) + fileType; // 通过MD5加密生成随机的文件名
        InputStream in = null;
        try {
            // 判断目标 bucket 是否存在
            boolean exit = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketNameOfMdPicture).build());
            if (!exit){
                // 创建名为 bucketName 的 bucket
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketNameOfMdPicture).build());
            }

            in = file.getInputStream();
            // 上传图片
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketNameOfMdPicture)
                            .object(fileName)
                            .stream(in,file.getSize(),-1)
                            .build()
            );
            // 获取头像路径
            String url = minioClient.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs
                            .builder()
                            .method(Method.GET)
                            .bucket(bucketNameOfMdPicture)
                            .object(fileName)
                            .build());
            return url;
        } catch (Exception e) {
            log.error(e.toString());
            e.printStackTrace();
            return "false";
        }finally {
            // 关闭流
            if (in != null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 发布error （接收的是JSON）
     * @return
     */
    @RequestMapping(value = "/publishPage/error", name = "发布error/user", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public String publishError(@RequestBody JSONObject jsonParam){
        try {
            Article article = JSON.parseObject(String.valueOf(jsonParam), Article.class);
            Error error = new Error();
            // 获取描述
            int length = article.getText().length();
            if (length>200){
                length = 200;
            }
            String describe = article.getText().substring(0, length - 1).replaceAll("\r|\n", "").trim();

            // 发布时
            if ("".equals(article.getArticleId())) {
                // 设置作者ID
                error.setUserId((String) httpServletRequest.getSession().getAttribute("userId"));
                // 设置标题
                error.setErrorTitle(article.getTitle());
                // 设置描述
                error.setErrorDescribe(describe);
                // 设置标签
                error.setErrorLabel(article.getLabels());
                // 设置发布时间
                error.setErrorDate(DateTimeUtils.currentDateTime2SQLTimestamp());
                // 设置文件名（文件路径）
                String fileName = uploadMD(article.getText(), null);
                if (!"false".equals(fileName)) {
                    error.setErrorAddr(fileName);
                    // 将相关信息插入数据库
                    int res = errorMapper.insert(error);
                    if (res == 1) {
                        sync2EsUtils.publishOpt(error.getErrorId()); // 同步es
                        return "true";
                    } else {
                        return "false";
                    }
                } else {
                    return "false";
                }
            } else {   // 更新时
                UpdateWrapper<Error> wrapper = new UpdateWrapper<>();
                wrapper.eq("error_id",article.getArticleId());
                wrapper.set("error_title",article.getTitle());
                wrapper.set("error_describe",describe);
                wrapper.set("error_label",article.getLabels());
                Error error1 = errorMapper.selectById(article.getArticleId());
                // 覆盖原本的 MD 文件
                String s = uploadMD(article.getText(), error1.getErrorAddr());
                if (!"false".equals(s)){
                    int res = errorMapper.update(null, wrapper);
                    if (res == 1) {
                        sync2EsUtils.updateOpt(article.getArticleId());  // 同步es
                        return "true";
                    } else {
                        return "false";
                    }
                } else {
                    return "false";
                }
            }

        } catch (Exception e) {
            log.error(e.toString());
            return "error";
        }
    }

    /**
     * 发布question （接收的是JSON）
     * @return
     */
    @RequestMapping(value = "/publishPage/question", name = "发布question/user", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public String publishQuestion(@RequestBody JSONObject jsonParam){
        try {
            Article article = JSON.parseObject(String.valueOf(jsonParam), Article.class);
            Question question = new Question();
            // 获取描述
            int length = article.getText().length();
            if (length>200){
                length = 200;
            }
            String describe = article.getText().substring(0, length - 1).replaceAll("\r|\n", "").trim();

            // 发布时
            if ("".equals(article.getArticleId())) {
                // 设置作者ID
                question.setUserId((String) httpServletRequest.getSession().getAttribute("userId"));
                // 设置标题
                question.setQuestionTitle(article.getTitle());
                // 设置描述
                question.setQuestionDescribe(describe);
                // 设置标签
                question.setQuestionLabel(article.getLabels());
                // 设置发布时间
                question.setQuestionDate(DateTimeUtils.currentDateTime2SQLTimestamp());
                // 设置文件名（文件路径）
                String fileName = uploadMD(article.getText(),null);
                if (!"false".equals(fileName)){
                    question.setQuestionAddr(fileName);
                    // 将相关信息插入数据库
                    int res = questionMapper.insert(question);
                    if (res == 1) {
                        sync2EsUtils.publishOpt(question.getQuestionId()); // 同步es
                        return "true";
                    } else {
                        return "false";
                    }
                } else {
                    return "false";
                }
            } else {  // 更新时
                UpdateWrapper<Question> wrapper = new UpdateWrapper<>();
                wrapper.eq("question_id",article.getArticleId());
                wrapper.set("question_title",article.getTitle());
                wrapper.set("question_describe",describe);
                wrapper.set("question_label",article.getLabels());
                Question question1 = questionMapper.selectById(article.getArticleId());
                // 覆盖原本的 MD 文件
                String s = uploadMD(article.getText(), question1.getQuestionAddr());
                if (!"false".equals(s)){
                    int res = questionMapper.update(null, wrapper);
                    if (res == 1) {
                        sync2EsUtils.updateOpt(article.getArticleId());  // 同步es
                        return "true";
                    } else {
                        return "false";
                    }
                } else {
                    return "false";
                }
            }
        } catch (Exception e) {
            log.error(e.toString());
            return "error";
        }
    }


    /**
     * 发布blink
     * @param jsonParam
     * @return
     */
    @RequestMapping(value = "/publishPage/blink", name = "发布blink/user", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public String blink(@RequestBody JSONObject jsonParam){
        try {
            BlinkInfo blinkInfo = JSON.parseObject(String.valueOf(jsonParam), BlinkInfo.class);
            // 发布时
            if ("".equals(blinkInfo.getBlinkId())){
                Blink blink = new Blink();
                blink.setUserId((String) httpServletRequest.getSession().getAttribute("userId"));
                blink.setBlinkContext(blinkInfo.getBlinkContent());
                blink.setBlinkDate(DateTimeUtils.currentDateTime2SQLTimestamp());
                int res = blinkMapper.insert(blink);
                if (res == 1){
                    return "true";
                } else {
                    return "false";
                }
            } else {  // 更新时
                UpdateWrapper<Blink> wrapper = new UpdateWrapper<>();
                wrapper.eq("blink_id",blinkInfo.getBlinkId());
                wrapper.set("blink_context",blinkInfo.getBlinkContent());
                int res = blinkMapper.update(null, wrapper);
                if (res == 1){
                    return "true";
                } else {
                    return "false";
                }
            }

        } catch (Exception e) {
            log.error(e.toString());
            return "error";
        }
    }

    /**
     * 上传MD文件，并返回文件名
     * @param str 用于生成MD文件
     * @param fileName 自定义文件名，主要用于更新文章时覆盖原本的文章
     * @return 返回的是上传到minio的文件的文件名
     */
    private String uploadMD(String str,String fileName){
        if (fileName == null){
            fileName = (UUID.randomUUID() + "").replaceAll("-","") + ".txt";
        }

        try {
            // 将String转换为InputStream
            InputStream in = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8));

            // 判断目标 bucket 是否存在
            boolean exit = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketNameOfMdFile).build());
            if (!exit){
                // 创建名为 bucketName 的 bucket
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketNameOfMdFile).build());
            }
            // 上传文件
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketNameOfMdFile)
                            .object(fileName)
                            .stream(in,in.available(),-1)
                            .build()
            );
            return fileName;
        } catch (Exception e) {
            log.error(e.toString());
            return "false";
        }
    }

    /**
     * 获取编辑error或者question的标题、描述、标签
     * @param workID
     * @return
     */
    @RequestMapping(value = "/publishPage/editWorkById/{workID}", name = "获取编辑error或者question的标题、描述、标签/user")
    public String editErrorById(@PathVariable String workID){
        try {
            // 根据 workID 判断 work的类型
            QueryWrapper<HotArticle> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("article_id",workID);
            List<HotArticle> articles = hotArticleMapper.selectList(queryWrapper);
            String classify = articles.get(0).getClassify();

            if ("error".equals(classify)) {
                Error error = errorMapper.selectById(workID);
                String markdownOfReply = getMarkdownOfReply(error.getErrorAddr());
                if (!"false".equals(markdownOfReply)) {
                    // 将 markdown 的文本回填到 errorAddr 的位置
//                    error.setErrorAddr(markdownOfReply);
                    error.setErrorAddr(updateUtil.updateMDOfImgURL(markdownOfReply, bucketNameOfMdPicture));
                } else {
                    error.setErrorAddr("`哎呀，真是抱歉，暂时没有内容...`");
                }
                return JSON.toJSONString(error);
            } else {
                Question question = questionMapper.selectById(workID);
                String markdownOfReply = getMarkdownOfReply(question.getQuestionAddr());
                if (!"false".equals(markdownOfReply)) {
                    // 将 markdown 的文本回填到 questionAddr 的位置
//                    question.setQuestionAddr(markdownOfReply);
                    question.setQuestionAddr(updateUtil.updateMDOfImgURL(markdownOfReply, bucketNameOfMdPicture));
                } else {
                    question.setQuestionAddr("`哎呀，真是抱歉，暂时没有内容...`");
                }
                return JSON.toJSONString(question);
            }
        } catch (Exception e) {
            log.error(e.toString());
            return "false";
        }
    }


    /**
     * 获取编辑 blink 的内容
     * @param workID
     * @return
     */
    @RequestMapping(value = "/publishPage/editBlink/{workID}", name = "获取编辑 blink 的内容/user")
    public String editBlink(@PathVariable String workID){
        try {
            Blink blink = blinkMapper.selectById(workID);
            return blink.getBlinkContext();
        } catch (Exception e) {
            log.error(e.toString());
            return "false";
        }
    }


    /**
     * 根据 filename 获取对应文件中的文本
     * @param fileName
     * @return
     */
    private String getMarkdownOfReply(String fileName) {
        try {
            // 从 minio 中获取文件流
            InputStream inputStream = minioClient.getObject(
                    GetObjectArgs.builder()
                            .bucket(bucketNameOfMdFile)
                            .object(fileName)
                            .build());

            // 将 InputStream 转换为 String
            String res = new BufferedReader(new InputStreamReader(inputStream))
                    .lines().collect(Collectors.joining(System.lineSeparator()));
            return res;

        } catch (Exception e) {
            log.error(e.toString());
            return "false";
        }
    }
}
